﻿using FlexFlow.Base;
using FlexFlow.Base.File;
using FlexFlow.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace FlexFlow.Runtime
{
    /// <summary>
    /// 表示用户数据管理器
    /// </summary>
    public class UserDataManager : ManagerBase
    {
        /// <summary>
        /// 获取或设置默认的用户数据管理器
        /// </summary>
        public static UserDataManager Default { get; set; }
        /// <summary>
        /// 表示当前用户数据的有效文件夹列表
        /// </summary>
        public static Dictionary<string, FilePathAccessMode> PathAccessModeSetting { get; private set; }
        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="contentStream">
        /// 文件内容流
        /// </param>
        /// <param name="des">
        /// 文件描述
        /// </param>
        /// <returns>
        /// 操作结果
        /// </returns>
        public OperateResult UploadFile(FileDescription des, Stream contentStream)
        {

            if (!CheckPathPermission(des.Path, FilePathAccessMode.Upload))
            {
                return new OperateResult()
                {
                    ResultCode = 0x040101,
                    Message = "该文件夹不允许上传文件！"
                };
            }
            Stream saveStream = this.Components.PhysicalFileManager.OpenFile(des, FileOpenMode.Write);
            contentStream.CopyTo(saveStream);
            saveStream.Flush();
            saveStream.Close();
            if (this.Components.FileDescriptionProvider.Add(des))
            {
                return OperateResult.SuccessResult(des.Identity);
            }
            else
            {
                this.Components.PhysicalFileManager.DeleteFile(des);
                return new OperateResult()
                {
                    ResultCode = 0x040102,
                    Message = "更新文件描述失败！"
                };
            }
        }
        /// <summary>
        /// 下载指定文件描述描述的物理文件
        /// </summary>
        /// <param name="des">
        /// 文件描述
        /// </param>
        /// <param name="outputStream">
        /// 表示文件内容的输出流
        /// </param>
        /// <returns>
        /// 操作结果
        /// </returns>
        public OperateResult DownloadFile(FileDescription des, Stream outputStream)
        {
            if (!CheckPathPermission(des.Path, FilePathAccessMode.Download))
            {
                return new OperateResult()
                {
                    ResultCode = 0x040201,
                    Message = "不允许下载该文件夹内的文件！"
                };
            }
            Stream loadStream = this.Components.PhysicalFileManager.OpenFile(des, FileOpenMode.Read);
            if (loadStream != null)
            {
                loadStream.CopyTo(outputStream);
                outputStream.Flush();
                loadStream.Close();
                return OperateResult.SuccessResult();
            }
            else
            {
                return new OperateResult()
                {
                    ResultCode = 0x040202,
                    Message = "打开文件失败！"
                };
            }
        }
        /// <summary>
        /// 下载指定ID的文件描述描述的物理文件
        /// </summary>
        /// <param name="fileDesId">
        /// 文件描述ID
        /// </param>
        /// <param name="outputStream">
        /// 表示文件内容的输出流
        /// </param>
        /// <returns>
        /// 操作结果
        /// </returns>
        public OperateResult DownloadFile(Guid fileDesId, Stream outputStream, out FileDescription des)
        {
            des = this.Components.FileDescriptionProvider.Get(fileDesId);
            if (des == null)
            {
                return new OperateResult()
                {
                    ResultCode = 0x040301,
                    Message = "指定的文件描述ID无效！"
                };
            }
            return DownloadFile(des, outputStream);
        }
        /// <summary>
        /// 删除具有指定ID的文件
        /// </summary>
        /// <param name="fileDesId">
        /// 要删除的文件ID
        /// </param>
        /// <returns>
        /// 操作结果
        /// </returns>
        public OperateResult DeleteFile(Guid fileDesId)
        {

            FileDescription des = this.Components.FileDescriptionProvider.Get(fileDesId);
            if (des == null)
            {
                return new OperateResult()
                {
                    ResultCode = 0x040401,
                    Message = "指定文件描述ID无效！"
                };
            }
            if (!CheckPathPermission(des.Path, FilePathAccessMode.Delete))
            {
                return new OperateResult()
                {
                    ResultCode = 0x040402,
                    Message = "不允许删除该文件夹下的文件！"
                };
            }
            string deleteErrs = this.Components.PhysicalFileManager.DeleteFile(des);
            if (deleteErrs != string.Empty && deleteErrs != "指定文件的物理文件已被删除！")
            {
                return new OperateResult()
                {
                    ResultCode = 0x040403,
                    Message = "删除文件失败：" + deleteErrs
                };
            }
            if (!this.Components.FileDescriptionProvider.Delete(fileDesId))
            {
                return new OperateResult()
                {
                    ResultCode = 0x040404,
                    Message = "删除文件描述失败！"
                };
            }
            return OperateResult.SuccessResult();
        }
        /// <summary>
        /// 取得指定上传者上传的所有文件
        /// </summary>
        /// <param name="uploader">
        /// 要取得上传文件的上传者ID
        /// </param>
        /// <param name="path">
        /// 要获取的文件所在的目录
        /// </param>
        /// <returns>
        /// 操作结果
        /// </returns>
        public OperateResult GetFiles(Guid uploader, string path = "UploadFiles")
        {
            if (!CheckPathPermission(path, FilePathAccessMode.List))
            {
                return new OperateResult()
                {
                    ResultCode = 0x040501,
                    Message = "不允许列出该文件夹下的文件！"
                };
            }
            return OperateResult.SuccessResult(this.Components.FileDescriptionProvider.GetFiles(uploader, path));
        }
        /// <summary>
        /// 检查指定路径是否具有指定权限
        /// </summary>
        /// <param name="path">
        /// 要检验的路径
        /// </param>
        /// <param name="mode">
        /// 要检验的权限
        /// </param>
        /// <param name="defaultMode">
        /// 若指定文件夹的访问权限没设置，则检验该值
        /// </param>
        /// <returns>
        /// 一个值，表示是否具有指定权限
        /// </returns>
        private bool CheckPathPermission(string path, FilePathAccessMode mode, FilePathAccessMode defaultMode = FilePathAccessMode.None)
        {
            try
            {
                FilePathAccessMode accMode = PathAccessModeSetting[path];
                return accMode.HasFlag(mode);
            }
            catch (KeyNotFoundException)
            {
                return defaultMode.HasFlag(mode);
            }
        }
        /// <summary>
        /// 初始化用户数据管理器的静态变量
        /// </summary>
        static UserDataManager()
        {
            Default = new UserDataManager();
            PathAccessModeSetting = new Dictionary<string, FilePathAccessMode>();
            PathAccessModeSetting.Add("UploadFiles", FilePathAccessMode.All);
            PathAccessModeSetting.Add("FormTemplates", FilePathAccessMode.All);
            PathAccessModeSetting.Add("ProcessDefines", FilePathAccessMode.List | FilePathAccessMode.Modify | FilePathAccessMode.Delete);
        }
    }
}
